package com.gyj.activiti.service.impl;

import com.gyj.activiti.dao.mapper.ApplyInfoMapper;
import com.gyj.activiti.dao.mapper.ApproveInfoMapper;
import com.gyj.activiti.model.ApplyInfo;
import com.gyj.activiti.model.ApproveInfo;
import com.gyj.activiti.service.ActivitiService;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * @author Gao
 * @date 2019/4/3
 */
@Service
public class ActivitiServiceImpl implements ActivitiService {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private ActivitiService activitiService;

    @Autowired
    private ApplyInfoMapper applyInfoMapper;

    @Autowired
    private ApproveInfoMapper approveInfoMapper;

    /**
     * 获取默认流程引擎实例，会自动读取activiti.cfg.xml文件
     */
    private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

    private final Logger log = LoggerFactory.getLogger(ActivitiServiceImpl.class);

    @Override
    public Integer insertApply(String processId, Byte days, String reason, String applyer) {
        ApplyInfo apply = new ApplyInfo();
        apply.setDays(days);
        apply.setReason(reason);
        apply.setVacationtype((byte) 2);
        apply.setProcessinstanceid(processId);
        //用户Id和申请人根据登录token获取
        apply.setUserid(111);
        apply.setApplyName(applyer);
        apply.setCreatetime(new Date());
        apply.setUpdatetime(new Date());
        return applyInfoMapper.insert(apply);
    }

    @Override
    public Integer insertApprove(Task task, String processId, String comment, Byte approveResult) {
        ApproveInfo approveInfo = new ApproveInfo();
        approveInfo.setAuditresult(approveResult);
        approveInfo.setProcessinstanceid(processId);
        approveInfo.setComment(comment);
        approveInfo.setAudittime(new Date());
        approveInfo.setTaskid(task.getId());
        approveInfo.setApprover("审批人根据token获取");
        return approveInfoMapper.insert(approveInfo);
    }

    @Override
    public InputStream getCurrentDiagram(String processId) {
        //获得流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processId).singleResult();
        String processDefinitionId = StringUtils.EMPTY;
        if (processInstance == null) {
            //查询已经结束的流程实例
            HistoricProcessInstance processInstanceHistory = processEngine.getHistoryService().createHistoricProcessInstanceQuery()
                    .processInstanceId(processId).singleResult();
            if (processInstanceHistory == null) {
                return null;
            } else {
                processDefinitionId = processInstanceHistory.getProcessDefinitionId();
            }
        } else {
            processDefinitionId = processInstance.getProcessDefinitionId();
        }
        //使用宋体
        String fontName = "宋体";
        //获取BPMN模型对象
        BpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
        //获取流程实例当前的节点，需要高亮显示
        List currentActs = Collections.EMPTY_LIST;
        if (processInstance != null) {
            currentActs = runtimeService.getActiveActivityIds(processInstance.getId());
        }

        return processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator()
                .generateDiagram(model, "png", currentActs, new ArrayList<String>(),
                        fontName, fontName, fontName, null, 1.0);
    }

    @Override
    public InputStream showHistoryFlowNodeImage(String processId) throws Exception {
        //获取历史流程实例
        HistoricProcessInstance historicProcessInstance = processEngine.getHistoryService().createHistoricProcessInstanceQuery()
                .processInstanceId(processId).singleResult();
        String processDefinitionId = StringUtils.EMPTY;
        if (historicProcessInstance == null) {
            throw new Exception();
        } else {
            // 获取流程定义
            processDefinitionId = historicProcessInstance.getProcessDefinitionId();
            // 获取流程历史中已执行节点，并按照节点在流程中执行先后顺序排序
            List<HistoricActivityInstance> historicActivityInstanceList = processEngine.getHistoryService().createHistoricActivityInstanceQuery()
                    .processInstanceId(processId).orderByHistoricActivityInstanceId().asc().list();
            // 已执行的节点ID集合
            List<String> executedActivityIdList = new ArrayList<String>();
            int index = 1;
            log.info("获取已经执行的节点ID");
            for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
                executedActivityIdList.add(activityInstance.getActivityId());
                log.info("第[" + index + "]个已执行节点=" + activityInstance.getActivityId() + " : " + activityInstance.getActivityName());
                index++;
            }
            //使用宋体
            String fontName = "宋体";
            //获取BPMN模型对象
            BpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
            InputStream inputStream = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator()
                    .generateDiagram(model, "png", executedActivityIdList, new ArrayList<String>(),
                            fontName, fontName, fontName, null, 1.0);
            return inputStream;
        }
    }

    @Override
    public InputStream showHistoryFlowNodeAndLineImage(String processId) throws Exception {
        //获取历史流程实例
        HistoricProcessInstance historicProcessInstance = processEngine.getHistoryService().createHistoricProcessInstanceQuery()
                .processInstanceId(processId).singleResult();
        String processDefinitionId = StringUtils.EMPTY;
        if (historicProcessInstance == null) {
            throw new Exception();
        } else {
            // 获取流程定义
            processDefinitionId = historicProcessInstance.getProcessDefinitionId();
            // 获取流程历史中已执行节点，并按照节点在流程中执行先后顺序排序
            List<HistoricActivityInstance> historicActivityInstanceList = processEngine.getHistoryService().createHistoricActivityInstanceQuery()
                    .processInstanceId(processId).orderByHistoricActivityInstanceId().asc().list();
            // 已执行的节点ID集合
            List<String> executedActivityIdList = new ArrayList<String>();
            int index = 1;
            //获取已经执行的节点ID
            for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
                executedActivityIdList.add(activityInstance.getActivityId());
                log.info("第[" + index + "]个已执行节点=" + activityInstance.getActivityId() + " : " + activityInstance.getActivityName());
                index++;
            }

            String fontName = "宋体";
            //获取BPMN模型对象
            BpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
            // 获取流程走过的线
            List<String> highLightedFlows = getHighLightedFlows(model, historicActivityInstanceList);
            InputStream inputStream = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator()
                    .generateDiagram(model, "png", executedActivityIdList, highLightedFlows,
                            fontName, fontName, fontName, null, 1.0);
            return inputStream;
        }
    }

    public List<String> getHighLightedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 用以保存高亮的线flowId
        List<String> highFlows = new ArrayList<String>();
        int historySize = historicActivityInstances.size();
        for (int i = 0; i < historicActivityInstances.size() - 1; i++) {
            // 对历史流程节点进行遍历, 到节点定义的详细信息
            FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(i).getActivityId());
            // 用以保存后续开始时间相同的节点
            List<FlowNode> sameStartTimeNodes = new ArrayList<FlowNode>();
            FlowNode sameActivityImpl1 = null;
            // 第一个节点
            HistoricActivityInstance activityimpl = historicActivityInstances.get(i);
            HistoricActivityInstance activityimp2 = null;
            for (int k = i + 1; k <= historySize - 1; k++) {
                // 后续第1个节点
                activityimp2 = historicActivityInstances.get(k);
                if (activityimpl.getActivityType().equals("userTask") && activityimp2.getActivityType().equals("userTask") &&
                        //都是usertask，且主节点与后续节点的开始时间相同，说明不是真实的后继节点
                        df.format(activityimpl.getStartTime()).equals(df.format(activityimp2.getStartTime()))) {
                } else {
                    //找到紧跟在后面的一个节点
                    sameActivityImpl1 = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(k).getActivityId());
                    break;
                }
            }
            //将后面第一个节点放在时间相同节点的集合里
            if (sameActivityImpl1 != null) {
                sameStartTimeNodes.add(sameActivityImpl1);
            }
            for (int j = i + 1; j < historySize - 1; j++) {
                //后续第一个节点
                HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);
                //后续第二个节点
                HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);
                //如果第一个节点和第二个节点开始时间相同保存
                if (df.format(activityImpl1.getStartTime()).equals(df.format(activityImpl2.getStartTime()))) {
                    FlowNode sameActivityImpl2 = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityImpl2.getActivityId());
                    sameStartTimeNodes.add(sameActivityImpl2);
                } else {
                    //有不相同跳出循环
                    break;
                }
            }
            // 取出节点的所有出去的线
            List<SequenceFlow> pvmTransitions = flowNode.getOutgoingFlows();
            // 对所有的线进行遍历
            for (SequenceFlow pvmTransition : pvmTransitions) {
                // 如果取出的线的目标节点存在时间相同的节点里，保存该线的id，进行高亮显示
                FlowNode pvmActivityImpl = (FlowNode) bpmnModel.getMainProcess().getFlowElement(pvmTransition.getTargetRef());
                if (sameStartTimeNodes.contains(pvmActivityImpl)) {
                    highFlows.add(pvmTransition.getId());
                }
            }
        }

        return highFlows;
    }

    /**
     * 获取流程走过的线
     */
    /*public List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinitionEntity,
                                            List<HistoricActivityInstance> historicActivityInstances) {
        List<String> highFlows = new ArrayList<String>();
        // 用以保存高亮的线flowId
        for (int i = 0; i < historicActivityInstances.size() - 1; i++) {
            // 对历史流程节点进行遍历
            ActivityImpl activityImpl = processDefinitionEntity.findActivity(historicActivityInstances.get(i).getActivityId());
            // 得到节点定义的详细信息
            List<ActivityImpl> sameStartTimeNodes = new ArrayList<ActivityImpl>();
            // 用以保存后需开始时间相同的节点
            ActivityImpl sameActivityImpl1 = processDefinitionEntity.findActivity(historicActivityInstances.get(i + 1).getActivityId());
            // 将后面第一个节点放在时间相同节点的集合里
            sameStartTimeNodes.add(sameActivityImpl1);
            for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {
                HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);
                // 后续第一个节点
                HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);
                // 后续第二个节点
                if (activityImpl1.getStartTime().equals(activityImpl2.getStartTime())) {
                    // 如果第一个节点和第二个节点开始时间相同保存
                    ActivityImpl sameActivityImpl2 = processDefinitionEntity.findActivity(activityImpl2.getActivityId());
                    sameStartTimeNodes.add(sameActivityImpl2);
                } else {
                    // 有不相同跳出循环
                    break;
                }
            }
            List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions();
            // 取出节点的所有出去的线
            for (PvmTransition pvmTransition : pvmTransitions) {
                // 对所有的线进行遍历
                ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition.getDestination();
                // 如果取出的线的目标节点存在时间相同的节点里，保存该线的id，进行高亮显示
                if (sameStartTimeNodes.contains(pvmActivityImpl)) {
                    highFlows.add(pvmTransition.getId());
                }
            }
        }
        return highFlows;
    }*/
}




